
package lar.system.opengl;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;

import lar.system.engine.MainProgram;
import lar.system.engine.UI;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;

public class GLImage implements Drawable
{
	private int resourceId;
	private float[] glPos, glDim;
	private FloatBuffer vertexBuffer;	
	private GLColor maskColor;
	private float rotation;
	private boolean repeat = false;
	private float xyRatio;
	private float vertices[] = 
	{
			-1.0f, -1.0f,  0.0f,		// V1 - bottom left
			-1.0f,  1.0f,  0.0f,		// V2 - top left
			 1.0f, -1.0f,  0.0f,		// V3 - bottom right
			 1.0f,  1.0f,  0.0f			// V4 - top right
	};

	private FloatBuffer textureBuffer;	
	private float texture[] = 
	{    		
			
			0.0f, 1.0f,		// top left		(V2)
			0.0f, 0.0f,		// bottom left	(V1)
			1.0f, 1.0f,		// top right	(V4)
			1.0f, 0.0f		// bottom right	(V3)
	};
	
	public GLImage(int resourceId, float[] glPos, float[] glDim) 
	{
		Constructor(resourceId, glPos, glDim);
	}
	
	/**
	 * Used for repeating textures.
	 * The image will fit in the shortest axis
	 * 
	 */
	public GLImage(int resourceId, float[] glPos, float[] glDim, float x_y_ratio) 
	{
		repeat = true;
		xyRatio = x_y_ratio;
		Constructor(resourceId, glPos, glDim);
	}
	
	public void Constructor(int resourceId, float[] glPos, float[] glDim) 
	{
		rotation = 0;
		maskColor = null;
		this.resourceId = resourceId;
		Bitmap bitmap = resourceId <= 0 ? null : BitmapFactory.decodeResource(MainProgram.currentActivity.getResources(), resourceId);
		if(bitmap != null)
		{
			int w = bitmap.getWidth();
			int h = bitmap.getHeight();
			bitmap.recycle();
			
			
			texture[4] = ((float)w)/((float)GLRenderer.nextPowerOfTwo(w));
			texture[6] = ((float)w)/((float)GLRenderer.nextPowerOfTwo(w));
			texture[1] = ((float)h)/((float)GLRenderer.nextPowerOfTwo(h));
			texture[5] = ((float)h)/((float)GLRenderer.nextPowerOfTwo(h));
		}
		this.glDim = glDim;
		this.glPos = glPos;
		ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
		byteBuffer.order(ByteOrder.nativeOrder());
		
		vertexBuffer = byteBuffer.asFloatBuffer();
		
		vertexBuffer.put(vertices);
		
		vertexBuffer.position(0);
		
		byteBuffer = ByteBuffer.allocateDirect(texture.length * 4);
		byteBuffer.order(ByteOrder.nativeOrder());
		textureBuffer = byteBuffer.asFloatBuffer();
		textureBuffer.put(texture);
		textureBuffer.position(0);
	}
	
	public GLImage(Bitmap bmp, int resourceId, float[] glPos, float[] glDim) 
	{
		rotation = 0;
		maskColor = null;
		this.resourceId = resourceId;
		int w = bmp.getWidth();
		int h = bmp.getHeight();
		
		this.glDim = glDim;
		this.glPos = glPos;
		texture[4] = ((float)w)/((float)GLRenderer.nextPowerOfTwo(w));
		texture[6] = ((float)w)/((float)GLRenderer.nextPowerOfTwo(w));
		texture[1] = ((float)h)/((float)GLRenderer.nextPowerOfTwo(h));
		texture[5] = ((float)h)/((float)GLRenderer.nextPowerOfTwo(h));
		ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
		byteBuffer.order(ByteOrder.nativeOrder());
		
		vertexBuffer = byteBuffer.asFloatBuffer();
		
		vertexBuffer.put(vertices);
		
		vertexBuffer.position(0);
		
		byteBuffer = ByteBuffer.allocateDirect(texture.length * 4);
		byteBuffer.order(ByteOrder.nativeOrder());
		textureBuffer = byteBuffer.asFloatBuffer();
		textureBuffer.put(texture);
		textureBuffer.position(0);
	}
	
	public void setMaskColor(GLColor c)
	{
		maskColor = c;
		UI.needRendering = true;
	}
	
	public float[] getGLPos()
	{
		return new float[]{glPos[0], glPos[1]};
	}
	
	public float[] getGLDim()
	{
		return new float[]{glDim[0], glDim[1]};
	}
	
	public GLColor getMaskColor()
	{
		return maskColor;
	}

	public int getResourceId()
	{
		return resourceId;
	}
	
	public void setGLCoords(float[] coords)
	{
		glPos = new float[]{coords[0], coords[1]};
		UI.needRendering = true;
	}
	
	public void setGLDims(float[] dims)
	{
		glDim = new float[]{dims[0], dims[1]};
		UI.needRendering = true;
	}
	
	public void setRotation(float rot)
	{
		rotation = rot;
		UI.needRendering = true;
	}
	
	public float getRotation()
	{
		return rotation;
	}
	
	public void Draw(GL11 gl) 
	{
		if(repeat) 
		{
			DrawRepeat(gl);
			return;
		}
		gl.glBindTexture(GL11.GL_TEXTURE_2D, MainProgram.glSurfaceView.renderer.ResourceIdToTexture(resourceId));
		gl.glEnableClientState(GL11.GL_VERTEX_ARRAY);
		gl.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
		gl.glFrontFace(GL11.GL_CW);
		gl.glVertexPointer(3, GL11.GL_FLOAT, 0, vertexBuffer);
		gl.glTexCoordPointer(2, GL11.GL_FLOAT, 0, textureBuffer);
		gl.glPushMatrix();
		gl.glTranslatef(glPos[0], glPos[1], -1.0f);
		gl.glScalef(glDim[0], glDim[1], 1.0f);
		gl.glRotatef(rotation, 0,0,-1);
		if(maskColor != null) maskColor.apply(gl);
		gl.glDrawArrays(GL11.GL_TRIANGLE_STRIP, 0, vertices.length / 3);
		if(maskColor != null) maskColor.restore(gl);
		gl.glPopMatrix();
		gl.glDisableClientState(GL11.GL_VERTEX_ARRAY);
		gl.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
	}

	public void DrawRepeat(GL11 gl)
	{
		float cur_xyratio = glDim[0]/glDim[1];
		float X = cur_xyratio / xyRatio;
		gl.glEnable(GL10.GL_SCISSOR_TEST);
		int[] scissorCoords = GLRenderer.getScissorCoords(glPos, glDim);
		gl.glScissor(scissorCoords[0],scissorCoords[1],scissorCoords[2],scissorCoords[3]);
		int texId = MainProgram.glSurfaceView.renderer.ResourceIdToTexture(resourceId);
		if(X > 1) //repeat left-right
		{
			for(int i = 0; i < X+1; i++)
			{
				gl.glBindTexture(GL11.GL_TEXTURE_2D, texId);
				gl.glEnableClientState(GL11.GL_VERTEX_ARRAY);
				gl.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
				gl.glFrontFace(GL11.GL_CW);
				gl.glVertexPointer(3, GL11.GL_FLOAT, 0, vertexBuffer);
				gl.glTexCoordPointer(2, GL11.GL_FLOAT, 0, textureBuffer);
				gl.glPushMatrix();
				gl.glTranslatef(glPos[0]-glDim[0]+(glDim[1]*xyRatio*(2*i+1)), glPos[1], -1.0f);
				gl.glScalef(glDim[1]*xyRatio, glDim[1], 1.0f);
				gl.glRotatef(rotation, 0,0,-1);
				if(maskColor != null) maskColor.apply(gl);
				gl.glDrawArrays(GL11.GL_TRIANGLE_STRIP, 0, vertices.length / 3);
				if(maskColor != null) maskColor.restore(gl);
				gl.glPopMatrix();
				gl.glDisableClientState(GL11.GL_VERTEX_ARRAY);
				gl.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
			}
		}
		else //repeat up-down
		{
			for(int i = 0; i < (1/X)+1; i++)
			{
				gl.glBindTexture(GL11.GL_TEXTURE_2D, texId);
				gl.glEnableClientState(GL11.GL_VERTEX_ARRAY);
				gl.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
				gl.glFrontFace(GL11.GL_CW);
				gl.glVertexPointer(3, GL11.GL_FLOAT, 0, vertexBuffer);
				gl.glTexCoordPointer(2, GL11.GL_FLOAT, 0, textureBuffer);
				gl.glPushMatrix();
				gl.glTranslatef(glPos[0], glPos[1]-glDim[1]+(glDim[0]*(1/xyRatio)*(2*i+1)), -1.0f);
				gl.glScalef(glDim[0], glDim[0]/xyRatio, 1.0f);
				gl.glRotatef(rotation, 0,0,-1); 
				if(maskColor != null) maskColor.apply(gl);
				gl.glDrawArrays(GL11.GL_TRIANGLE_STRIP, 0, vertices.length / 3);
				if(maskColor != null) maskColor.restore(gl);
				gl.glPopMatrix();
				gl.glDisableClientState(GL11.GL_VERTEX_ARRAY);
				gl.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
			}
		}
		gl.glDisable(GL10.GL_SCISSOR_TEST);
	}

	public boolean CheckBounds(float x, float y) 
	{
		if(x > glPos[0]+Math.abs(glDim[0]) || x < glPos[0]-Math.abs(glDim[0])) return false;
		if(y > glPos[1]+Math.abs(glDim[1]) || y < glPos[1]-Math.abs(glDim[1])) return false;
		return true;
	}
}
